package moveresize;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

class MoveResize {
	static final int BORDER_THICKNESS = 4;

	static Rectangle to(Rectangle bounds) {
		final Rectangle[] rectangle = new Rectangle[1];
		Display display = new Display();
		initialize(display);
		final Shell shell = new Shell(display, SWT.NO_TRIM);
		shell.setText(MoveResize.class.getSimpleName());
		shell.setBounds(display.getBounds());
		/* Take the screen shot */
        GC gc = new GC(display);
        final Image desktopImage = new Image(display, shell.getBounds());
        gc.copyArea(desktopImage, shell.getBounds().x, shell.getBounds().y);
        gc.dispose();
        final PaintListener paintListener = new ImagePainter(desktopImage);
        shell.addPaintListener(paintListener);
        shell.setLayout(null);
		final Canvas canvas = new Canvas(shell, SWT.NO_BACKGROUND);
		configure(display, canvas, bounds);
		canvas.addKeyListener(new KeyListener() {
			public void keyPressed(KeyEvent e) {}
			public void keyReleased(KeyEvent e) {
				if (e.character == '?') {
					help(shell);
				} else if (e.keyCode == SWT.ESC) {
					close(shell, canvas);
				} else if (e.keyCode == SWT.CR) {
					rectangle[0] = canvas.getBounds();
					close(shell, canvas);
				}
			}
		});
		
        shell.addKeyListener(new KeyListener() {
			public void keyPressed(KeyEvent e) {}
			public void keyReleased(KeyEvent e) {
				if (e.keyCode == SWT.ESC) {
					close(shell, canvas);
				} else if (e.keyCode == SWT.CR) {
					rectangle[0] = canvas.getBounds();
					close(shell, canvas);
				}
			}
		});
        
        shell.addMouseListener(new MouseAdapter() {
        	public void mouseUp(MouseEvent e) {
				close(shell, canvas);
        	}
        });
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		desktopImage.dispose();
		display.dispose();
		return rectangle[0];
	}

	private static void close(final Shell shell, Canvas canvas) {
		canvas.setCursor(CURSOR_ARROW);
		shell.setCursor(CURSOR_ARROW);
		shell.setVisible(false);
		shell.close();
	}
	
	private static void configure(Display display, Control control, Rectangle bounds) {
        final PaintListener paintListener = new TintPainter();
        control.addPaintListener(paintListener);
		control.setBounds(bounds);
		new Resizer(control).attach();
		new BoundsHistory(control).attach();
	}
	
	static Cursor getCursor(int c) {
		switch (c) {
		case SWT.CURSOR_ARROW:
			return CURSOR_ARROW;
		case SWT.CURSOR_SIZEN:
			return CURSOR_N;
		case SWT.CURSOR_SIZEE:
			return CURSOR_E;
		case SWT.CURSOR_SIZEW:
			return CURSOR_W;
		case SWT.CURSOR_SIZES:
			return CURSOR_S;
		case SWT.CURSOR_SIZENE:
			return CURSOR_NE;
		case SWT.CURSOR_SIZENW:
			return CURSOR_NW;
		case SWT.CURSOR_SIZESE:
			return CURSOR_SE;
		case SWT.CURSOR_SIZESW:
			return CURSOR_SW;
		case SWT.CURSOR_SIZEALL:
			return CURSOR_MOVE;
		}
		return CURSOR_ARROW;
	}
	
	static void help() {
		help(null);
	}
	
	private static void help(Shell parent) {
		Shell nonFinalShell = null;
		if (parent == null) {
			nonFinalShell = new Shell(Display.getCurrent(), SWT.APPLICATION_MODAL | SWT.CLOSE | SWT.RESIZE);
		} else {
			nonFinalShell = new Shell(parent, SWT.APPLICATION_MODAL | SWT.CLOSE | SWT.RESIZE);
		}
		final Shell shell = nonFinalShell;
		shell.setLayout(new FillLayout());
		Table table = new Table(shell, SWT.BORDER | SWT.FULL_SELECTION | SWT.HIDE_SELECTION);
		TableColumn keyboardShortcut = new TableColumn(table, SWT.NONE);
		TableColumn description = new TableColumn(table, SWT.NONE);
		TableItem item;
		
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"0", "take full size of screen"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"1", "take size of screen minus menubar"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"2", "take half size of screen"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"4", "take quarter size of screen"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"=", "center window"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"| or h", "take height of screen"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"- or w", "take width of screen"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"^", "move to the top edge of the screen"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"v", "move to the bottom edge of the screen"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"[", "move to the left edge of the screen"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"]", "move to the right edge of the screen"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"z", "go backwards in the bounds history"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"y", "go forward in the bounds history"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"x", "toggle between grow and shrink mode. grow mode is default."});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2191", "move window up by 10 pixels"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u21e7\u2191", "move window up by 100 pixels"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2191", "move window up by 1 pixel"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2193", "move window down by 10 pixels"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u21e7\u2193", "move window down by 100 pixels"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2193", "move window down by 1 pixel"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2190", "move window left by 10 pixels"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u21e7\u2190", "move window left by 100 pixels"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2190", "move window left by 1 pixel"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2192", "move window right by 10 pixels"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u21e7\u2192", "move window right by 100 pixels"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2192", "move window right by 1 pixel"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"Grow mode", ""});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u2191", "grow window by 10 pixels from top edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u21e7\u2191", "grow window by 100 pixels from top edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2325\u2191", "grow window by 1 pixels from top edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u2193", "grow window by 10 pixels from top edge from bottom edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u21e7\u2193", "grow window by 100 pixels from bottom edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2325\u2193", "grow window by 1 pixels from bottom edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u2190", "grow window by 10 pixels from top edge from left edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u21e7\u2190", "grow window by 100 pixels from left edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2325\u2190", "grow window by 1 pixels from left edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u2192", "grow window by 10 pixels from top edge from right edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u21e7\u2192", "grow window by 100 pixels from right edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2325\u2192", "grow window by 1 pixels from right edge "});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"Shrink mode", ""});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u2191", "shrink window by 10 pixels from bottom edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u21e7\u2191", "shrink window by 100 pixels from bottom edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2325\u2191", "shrink window by 1 pixels from bottom edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u2193", "shrink window by 10 pixels from top edge from top edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u21e7\u2193", "shrink window by 100 pixels from top edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2325\u2193", "shrink window by 1 pixels from top edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u2190", "shrink window by 10 pixels from top edge from right edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u21e7\u2190", "shrink window by 100 pixels from right edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2325\u2190", "shrink window by 1 pixels from right edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u2192", "shrink window by 10 pixels from top edge from left edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2325\u21e7\u2192", "shrink window by 100 pixels from left edge"});
		item = new TableItem(table, SWT.NONE);
		item.setText(new String[] {"\u2303\u2325\u2192", "shrink window by 1 pixels from left edge"});
		
		table.setSelection(0);
		table.deselectAll();
		
		TableItem[] items = table.getItems();
		for (int i = 0; i < items.length; i++) {
			if (i%2 == 0) {
				items[i].setBackground(ODD_ROW_COLOR);
			}
		}
		
		keyboardShortcut.pack();
		description.pack();
		shell.setBounds(200, 100, 465, 500);
		
        shell.addKeyListener(new KeyListener() {
			public void keyPressed(KeyEvent e) {}
			public void keyReleased(KeyEvent e) {
				if (e.keyCode == SWT.ESC) {
					e.doit = false;
					shell.close();
				}
			}
		});
		
		shell.open();
		while (!shell.isDisposed()) {
			if (!shell.getDisplay().readAndDispatch())
				shell.getDisplay().sleep();
		}
	}
	
	private static Cursor CURSOR_ARROW = null;
	private static Cursor CURSOR_MOVE = null;
	private static Cursor CURSOR_N = null;
	private static Cursor CURSOR_E = null;
	private static Cursor CURSOR_W = null;
	private static Cursor CURSOR_S = null;
	private static Cursor CURSOR_NE = null;
	private static Cursor CURSOR_NW = null;
	private static Cursor CURSOR_SE = null;
	private static Cursor CURSOR_SW = null;
	
	private static Font LARGE_FONT;
	
	private static Color ODD_ROW_COLOR;
	
	private static boolean initialized = false;
	
	private static void initialize(Display display) {
		if (!initialized) {
			CURSOR_ARROW = display.getSystemCursor(SWT.CURSOR_ARROW);
			CURSOR_MOVE = new Cursor(display, new ImageData(MoveResize.class.getResourceAsStream("CURSOR_MOVE.png")), 7, 7);
			CURSOR_N = new Cursor(display, new ImageData(MoveResize.class.getResourceAsStream("CURSOR_N.png")), 7, 0);
			CURSOR_E = new Cursor(display, new ImageData(MoveResize.class.getResourceAsStream("CURSOR_E.png")), 15, 7);
			CURSOR_W = new Cursor(display, new ImageData(MoveResize.class.getResourceAsStream("CURSOR_W.png")), 0, 7);
			CURSOR_S = new Cursor(display, new ImageData(MoveResize.class.getResourceAsStream("CURSOR_S.png")), 7, 15);
			CURSOR_NE = new Cursor(display, new ImageData(MoveResize.class.getResourceAsStream("CURSOR_NE.png")), 15, 0);
			CURSOR_NW = new Cursor(display, new ImageData(MoveResize.class.getResourceAsStream("CURSOR_NW.png")), 0, 0);
			CURSOR_SE = new Cursor(display, new ImageData(MoveResize.class.getResourceAsStream("CURSOR_SE.png")), 15, 15);
			CURSOR_SW = new Cursor(display, new ImageData(MoveResize.class.getResourceAsStream("CURSOR_SW.png")), 0, 15);
			
			LARGE_FONT = new Font(display, "Monaco", 16, SWT.NORMAL);
			
			ODD_ROW_COLOR = new Color(display, 240,240, 250);
		}
	}
	
	private static class ImagePainter implements PaintListener {
		private final Image image;

		ImagePainter(Image image) {
			this.image = image;
		}
		public void paintControl(PaintEvent e) {
			e.gc.drawImage(image, 0, 0);
		}		
	};
	
	private static class TintPainter implements PaintListener {
		TintPainter() {
		}
		
		public void paintControl(PaintEvent e) {
			GC gc = e.gc;
			gc.setAlpha(32);
			Canvas canvas = (Canvas) e.widget;
			Rectangle bounds = canvas.getBounds();
			gc.setBackground(e.display.getSystemColor(SWT.COLOR_DARK_BLUE));
			gc.fillRoundRectangle(
					0,
					0,
					bounds.width,
					bounds.height,
					BORDER_THICKNESS*2,
					BORDER_THICKNESS*2);
			gc.setAlpha(255);
			gc.setForeground(e.display.getSystemColor(SWT.COLOR_DARK_BLUE));
			for (int i = 0; i < 2; i++) {
				gc.drawRoundRectangle(
						i,
						i,
						bounds.width -1 - (2*i),
						bounds.height -1 - (2*i),
						BORDER_THICKNESS*2,
						BORDER_THICKNESS*2);
			}		
			
			gc.setBackground(e.display.getSystemColor(SWT.COLOR_BLACK));
			gc.setForeground(e.display.getSystemColor(SWT.COLOR_WHITE));
			String boundsInfo = 
				""
				+ "Location   : " + format(bounds.x)     + " , " + format(bounds.y) + "\n"
				+ "Size       : " + format(bounds.width) + " x " + format(bounds.height) + "\n"
				+ "(alt) Mode : " + (Resizer.isShrink(canvas) ? "\u2b1c to \u2597" : "\u2597 to \u2b1d")+ "\n"
				+ "Help       : " + "type ?"
				;
			gc.setFont(LARGE_FONT);
			Point textExtent = gc.textExtent(boundsInfo, SWT.DRAW_DELIMITER);
			gc.setAlpha(196);
			gc.fillRoundRectangle(
					((bounds.width-textExtent.x)/2)-(BORDER_THICKNESS*2),
					((bounds.height-textExtent.y)/2)-(BORDER_THICKNESS*2),
					textExtent.x+(BORDER_THICKNESS*4),
					textExtent.y+(BORDER_THICKNESS*2),
					BORDER_THICKNESS*2,
					BORDER_THICKNESS*2);
			gc.setAlpha(255);
			gc.drawText(boundsInfo, (bounds.width-textExtent.x)/2, ((bounds.height-textExtent.y)/2)-BORDER_THICKNESS, SWT.DRAW_DELIMITER | SWT.DRAW_TRANSPARENT);
		}

		private static String format(int i) {
			return String.format("%1$-4d", i);
		}		
	};

}
